﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using Platform.Linq;
using Platform.ObjectModel;
using Platform.ObjectModel.Design;
using Platform.Storage.Impl;

namespace Platform.Storage.Entity
{

	/// <summary>
	/// 
	/// </summary>
	/// <typeparam name="TData"></typeparam>
	internal sealed class EntityDynamicQuery<TData> : IQueryable<TData>, IQueryResolver
	{

		/// <summary>
		/// 
		/// </summary>
		/// <param name="dbContext"></param>
		/// <param name="provider"></param>
		/// <param name="library"></param>
		//internal EntityDynamicQuery( DataObjectContext dbContext, IQueryProvider provider, Library library )
		internal EntityDynamicQuery( IQueryable<FieldValue> fields, IQueryable<DataObjectRelationship> relations, IQueryProvider provider, Library library )
		{
			Debug.Assert( fields != null );
			Debug.Assert( relations != null );

			this.Provider = provider;
			//this.DbContext = dbContext;
			this.Library = library;
			this.Fields = fields;
			this.Relations = relations;

			this.Expression = Expression.Constant( this );
		}

		/// <summary>
		/// Obtém o contexto do entity
		/// </summary>
		//public DataObjectContext DbContext
		//{
		//	get;
		//	private set;
		//}

		/// <summary>
		/// Obtém a biblioteca de documentos que gerou essa query
		/// </summary>
		public Library Library
		{ get; private set; }

		#region IQueryResolver Members

		public IQueryable<FieldValue> Fields
		{
			get;
			private set;
			//get { return this.DbContext.Values; }
		}

		public IQueryable<FieldValue> Index
		{
			get { throw new NotImplementedException(); }
		}

		public IQueryable<DataObjectRelationship> Relations
		{
			get;
			private set;
			//get { return this.DbContext.Relationships; }
		}

		public bool TryGetSchema( Type entityType, out Schema schema )
		{
			schema = this.Library.Workspace.GetSchema( entityType );
			return schema != null;
		}

		public DataObjectName GetDataObjectName( Type entityType )
		{
			return this.GetSchema( entityType ).QualifiedName;
		}

		public DataObjectName GetFieldKey( Type entityType )
		{
			var schema = this.GetSchema( entityType );
			return schema.FieldKey;
		}

		#endregion


		private Schema GetSchema( Type entityType )
		{
			var schema = this.Library.Workspace.GetSchema( entityType );

			Debug.Assert( schema != null, String.Format( "O binding para o tipo \"{0}\" não foi encontrado.", entityType.FullName ) );
			return schema;
		}

		#region IEnumerable<TData> Members

		public IEnumerator<TData> GetEnumerator()
		{
			return this.Provider.Execute<IEnumerable<TData>>( this.Expression ).GetEnumerator();

		}

		#endregion

		#region IEnumerable Members

		System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
		{
			throw new NotImplementedException();
		}

		#endregion

		#region IQueryable Members

		public Type ElementType
		{
			get { return typeof( TData ); }
		}

		public System.Linq.Expressions.Expression Expression
		{
			get;
			internal set;
		}

		public IQueryProvider Provider
		{
			get;
			private set;
		}

		#endregion
	}

}
